const httpOnlyPrefix = '#HttpOnly_';

/**
 * This class is responsible for parsing and formatting cookies to the
 * Netscape format.
 */
export class NetscapeFormat {
  /**
   * Parses a string of cookie in the Netscape format to a cookie object.
   * @param {string} cookieString Cookies in the Netscape format.
   * @return {object} List of Cookies.
   */
  static parse(cookieString) {
    const cookies = [];
    const lines = cookieString.split('\n');
    for (let line of lines) {
      line = line.trim();
      if (!line.length) {
        continue;
      }
      const isHttpOnly = line.startsWith(httpOnlyPrefix);
      if (isHttpOnly) {
        line = line.substring(httpOnlyPrefix.length);
      }
      // Skip comments
      if (line[0] == '#') {
        continue;
      }

      const elements = line.split('\t');
      if (elements.length != 7) {
        throw new Error('Invalid netscape format');
      }
      cookies.push({
        domain: elements[0],
        hostOnly: elements[1].toLowerCase() === 'false',
        path: elements[2],
        secure: elements[3].toLowerCase() === 'true',
        expiration: elements[4],
        name: elements[5],
        value: elements[6],
        httpOnly: isHttpOnly,
      });
    }
    return cookies;
  }

  /**
   * Formats a list of cookies into a Netscape formatted string.
   * @param {Cookie[]} cookies Cookies to format.
   * @return {string} Netscape formatted cookie string.
   */
  static format(cookies) {
    let netscapeCookies = '# Netscape HTTP Cookie File';
    netscapeCookies += '\n# http://curl.haxx.se/rfc/cookie_spec.html';
    netscapeCookies += '\n# This file was generated by Cookie-Editor';
    for (const cookieId in cookies) {
      if (!Object.prototype.hasOwnProperty.call(cookies, cookieId)) {
        continue;
      }
      const cookie = cookies[cookieId].cookie;
      const secure = cookie.secure.toString().toUpperCase();
      let expiration = 0;

      if (cookie.session) {
        // Create sessions with a 1 day TTL to avoid the cookie being
        // discarded when imported back. This is a compromise due to the
        // Netscape format. It is short enough but not too short.
        expiration = Math.trunc(
          new Date(Date.now() + 86400 * 1000).getTime() / 1000
        );
      } else if (!cookie.session && !!cookie.expirationDate) {
        expiration = Math.trunc(cookie.expirationDate);
      }
      const includesSubdomain = cookie.hostOnly ? 'FALSE' : 'TRUE';

      const httpOnly = cookie.httpOnly ? httpOnlyPrefix : '';

      netscapeCookies +=
        `\n${httpOnly}${cookie.domain}	${includesSubdomain}	` +
        `${cookie.path}	${secure}	${expiration}	${cookie.name}` +
        `	${cookie.value}`;
    }
    return netscapeCookies;
  }
}
